package javawdw.security.dao.impl;

import java.lang.reflect.ParameterizedType;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javawdw.security.dao.CommonDao;

import org.springframework.dao.DataAccessException;
import org.springframework.dao.DataRetrievalFailureException;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import org.springframework.util.Assert;

@SuppressWarnings("unchecked")
public class AbstractDaoImpl<E> extends HibernateDaoSupport implements CommonDao<E> {
	private static final Map<String, Object> map = new HashMap<String, Object>();

	public E saveOrUpdate(E instance) throws DataAccessException,
			IllegalArgumentException {
		Assert.notNull(instance, "The instance must not be null");
		getSession().merge(instance);
		logger.debug("create(" + instance.toString() + ")");
		return instance;
	}

	public E delete(String id) throws DataAccessException,
			DataRetrievalFailureException, IllegalArgumentException {
		E e = findFirstByProperty("id", id);
		if (e != null) {
			getHibernateTemplate().delete(e);
		}
		return e;
	}

	public E findFirstByProperty(String name, Object value)
			throws DataAccessException, DataRetrievalFailureException,
			IllegalArgumentException {
		map.put(name, value);
		List<E> list = this.find(map);
		map.clear();
		return list != null && list.size() > 0 ? list.get(0) : null;
	}

	public List<E> find(Map<String, Object> properties)
			throws DataAccessException, DataRetrievalFailureException,
			IllegalArgumentException {
		String hql = "FROM " + getGenericClass().getSimpleName() + " WHERE 1=1";
		String orderBy = " ORDER BY updateTime";
		if (properties != null && properties.size() != 0) {
			Set<String> set = properties.keySet();
			for (String name: set) {
				if (name != null && !name.trim().equals("")) {
					hql += "AND " + name + "=?";
				}
			}
			return getHibernateTemplate().find(hql + orderBy, properties.values().toArray());
		}
		return getHibernateTemplate().find(hql + orderBy);
	}
	
	private Class<E> getGenericClass() {
		ParameterizedType type = (ParameterizedType) this.getClass().getGenericSuperclass();
		return (Class<E>) type.getActualTypeArguments()[0];
	}
}